/****************************************************************************************************
 *
 * File: SymbolTable.java
 * A General Symbol Table
 * Programmer: Leonidas Fegaras, UTA
 * Date: 4/10/03
 *
 ****************************************************************************************************/


/* A symbol in the symbol table */
class SymbolCell {
    String     name;
    Ast        binding; 
    SymbolCell next;
    SymbolCell ( String n, Ast v, SymbolCell r ) { name=n; binding=v; next=r; }
}


public class SymbolTable {

    final int symbol_table_size = 997;

    SymbolCell[] symbol_table = new SymbolCell[symbol_table_size];

    final int scope_stack_length = 100;

    int scope_stack_top = 0;

    int[] scope_stack = new int[scope_stack_length];

    public SymbolTable () {
	scope_stack_top = 0;
	for (int i = 0; i<symbol_table_size; i++)
	    symbol_table[i] = null;
    }

    static void fatal_error ( String msg, Ast x ) {
	throw new Error("*** Fatal error: " + msg + x);
    }

    /* a hashing function for strings */
    int hash ( String s ) {
	return Math.abs(s.hashCode()) % symbol_table_size;
    }

    /* insert a new item in the symbol table */
    public void insert ( String key, Ast binding ) {
	int loc = hash(key);
	symbol_table[loc] = new SymbolCell(key,binding,symbol_table[loc]);
	if (scope_stack_top >= scope_stack_length)
	   fatal_error("stack overflow",new Variable(key));
	else scope_stack[scope_stack_top++] = loc;
    }

    /* replace an item with a given name in the symbol table */
    public void replace ( String key, Ast binding ) {
	int loc = hash(key);
	for (SymbolCell s = symbol_table[loc]; s != null; s=s.next)
	    if (s.name.equals(key))
		s.binding = binding;
    }

    /* lookup for an item in the symbol table */
    public Ast lookup ( String key ) {
	int loc = hash(key);
	for (SymbolCell s = symbol_table[loc]; s != null; s=s.next)
	    if (s.name.equals(key))
	       return s.binding;
	return null;       // if not found
    }

    /* start a new environment */
    public void begin_scope () {
	if (scope_stack_top >= scope_stack_length)
	   fatal_error("stack overflow",new Number(0));
	else scope_stack[scope_stack_top++] = -1;
    }

    /* pop the last environment */
    public void end_scope () {
	int i = scope_stack_top-1;
	for (; scope_stack[i]>=0 && i>0; i--) {
	    int loc = scope_stack[i];
	    symbol_table[loc] = symbol_table[loc].next;
	};
	scope_stack_top = i;
    }

    /* display the content of the symbol table */
    public void display () {
	SymbolCell[] s = new SymbolCell[symbol_table_size];
	for (int i = 0; i<symbol_table_size; i++)
	    s[i] = symbol_table[i];
	for (int i = scope_stack_top-1; i>=0; i--)
	    if (scope_stack[i] == -1)
	       System.out.println("----------------");
	    else { SymbolCell c = s[scope_stack[i]];
	           s[scope_stack[i]] = c.next;
		   System.out.println(c.name + ": " + c.binding);
	         }
    }
}
